#include <head.h>
#include <sqlite3.h>
#include "emp.h"
#include <sys/epoll.h>
//服务器端，员工管理系统
#define DATEBASE "emp.db"
//处理收发数据函数
int do_analysis(int afd, sqlite3 *my_db, struct sockaddr_in clientaddr);
void my_login(int afd, sqlite3 *my_db, NETDATA_t *msg);
void my_search(int afd, sqlite3 *my_db, NETDATA_t *msg);
void my_modify(int afd, sqlite3 *my_db, NETDATA_t *msg);
void my_add(int afd, sqlite3 *my_db, NETDATA_t *msg);
void my_del(int afd, sqlite3 *my_db, NETDATA_t *msg);

//主函数
int main(int argc, const char *argv[])
{
    //校验参数
    if (3 != argc)
    {
        printf("Input error,try again!");
        printf("Usage:%s <IP> <port>", argv[0]);
        exit(-1);
    }
    int sockfd = 0;
    int accfd = 0;
    int ret, epfd, i;
    sqlite3 *my_db;
    //打开数据库（提前创建好数据表）
    if (SQLITE_OK != sqlite3_open(DATEBASE, &my_db))
    {
        printf("%s:%d -- errstr[%s]\n", __FILE__, __LINE__, sqlite3_errmsg(my_db));
        exit(-1);
    }

    // 1.创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
        ERRLOG("sockfd error\n");

    // 2.填充并绑定网络信息结构体
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;                 // IPV4
    serveraddr.sin_port = htons(atoi(argv[2]));      // port
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]); // ip
    socklen_t serveraddr_len = sizeof(serveraddr);   //网络信息结构体大小

    // 2.1定义客户信息结构体
    struct sockaddr_in clientaddr;
    socklen_t clientaddr_len = sizeof(clientaddr);
    // 2.2绑定网络信息结构体
    if (-1 == (ret = bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)))
        ERRLOG("bind error\n");

    //创建epoll
    if (-1 == (epfd = epoll_create(10)))
        ERRLOG("create epoll error\n");

    // 3.将socket设置为监听状态
    if (-1 == (ret = listen(sockfd, 5)))
        ERRLOG("listen error\n");

    //将sockfd添加到epoll监视的fd
    struct epoll_event event;
    struct epoll_event revents[10];
    event.data.fd = sockfd;
    event.events = EPOLLIN;
    if (-1 == (ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event)))
        ERRLOG("epoll_ctl sockfd error\n");

    while (1)
    {
        //等待sockfd就绪则有新的客户端连接，等待accfd就绪则有消息要收发
        if (-1 == (ret = epoll_wait(epfd, revents, 10, -1)))
            ERRLOG("epoll_wait error\n");
        for (i = 0; i < ret; i++)
        {
            if (revents[i].events & EPOLLIN)
            {
                if (sockfd == revents[i].data.fd)
                {
                    // sockfd就绪，有新客户端连接
                    if (-1 == (accfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_len)))
                        ERRLOG("accept error");
                    printf("客户端[%s][%d]已成功连接^_^\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
                    //将accfd添加到epoll监视的fd
                    event.data.fd = accfd;
                    event.events = EPOLLIN;
                    if (-1 == (ret = epoll_ctl(epfd, EPOLL_CTL_ADD, accfd, &event)))
                        ERRLOG("epoll_ctl sockfd error\n");
                }
                else
                {
                    //有accfd就绪，有数据发送过来
                    if (-1 == do_analysis(revents[i].data.fd, my_db, clientaddr))
                    {
                        if (-1 == (ret = epoll_ctl(epfd, EPOLL_CTL_DEL, revents[i].data.fd, &event)))
                            ERRLOG("epoll_ctl sockfd error\n");
                        close(accfd);
                        continue;
                    }
                }
            }
        }
    }
    close(sockfd);
    return 0;
}

//处理收发数据函数
int do_analysis(int afd, sqlite3 *my_db, struct sockaddr_in addr)
{
    NETDATA_t msg;
    bzero(&msg, sizeof(msg));
    int ret;
    //接收数据包
    if (-1 == (ret = recv(afd, &msg, sizeof(msg), 0)))
    {
        ERRLOG("recv");
    }
    else if (0 == ret)
    {
        printf("[%s][%d]已断开连接..\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        return -1;
    }
    //处理数据包
    switch (msg.oper_mod)
    {
    case LOGIN:
        //登录操作
        my_login(afd, my_db, &msg);
        break;
    case FIND:
        //查找操作
        my_search(afd, my_db, &msg);
        break;
    case CHANGE:
        //修改操作
        my_modify(afd, my_db, &msg);
        break;
    case ADD:
        //添加操作
        if (msg.aut_man != 1)
        {
            printf("越权操作，已终止\n");
            exit(-1);
        }
        my_add(afd, my_db, &msg);
        break;
    case DEL:
        //删除操作
        if (msg.aut_man != 1)
        {
            printf("越权操作，已终止\n");
            exit(-1);
        }
        my_del(afd, my_db, &msg);
        break;
    case QUIT:
        //客户端退出
        printf("[%s][%d]已退出..\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        return -1;
        break;
    default:
        printf("操作码错误\n");
        break;
    }
    return 0;
}

//登录函数
void my_login(int afd, sqlite3 *my_db, NETDATA_t *msg)
{
    char buf[128] = {0};
    char *errmsg, **result;
    int nrow, ncolumn;

    //通过sqlite3_get_table函数查询记录是否存在
    sprintf(buf, "select * from staff where name = '%s' and password = '%s'", msg->user.name, msg->user.password);
    if (sqlite3_get_table(my_db, buf, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
    {
        printf("error : %s\n", errmsg);
    }
    //通过nrow参数判断是否能够查询到记录，如果值为0，则查询不到，如果值为非0，则查询到
    if (nrow == 0)
    {
        msg->oper_mod = MY_F;
    }
    else
    {
        msg->oper_mod = MY_S;
        printf("%s已登陆成功\n", msg->user.name);
    }
    if (!strcmp("lrx", msg->user.name))
    { // lrx为管理员
        msg->aut_man = 1;
    }
    //发送登录回复信息
    if (-1 == send(afd, msg, sizeof(NETDATA_t), 0))
    {
        ERRLOG("login_send");
    }

    return;
}

//查询回调函数
int callback(void *arg, int ncolumn, char **f_value, char **f_name)
{
    struct call
    {
        int fd;
        char name[32];
    } arg_m;
    arg_m = *(struct call *)arg;
    NETDATA_t msg;
    // id|name|password|age|position|tel|addr|salary
    //组装发送包结构体
    msg.info.id = atoi(f_value[0]);
    strcpy(msg.info.name, f_value[1]);
    msg.info.age = atoi(f_value[3]);
    strcpy(msg.info.position, f_value[4]);
    strcpy(msg.info.tel, f_value[5]);
    strcpy(msg.info.addr, f_value[6]);
    msg.info.salary = atof(f_value[7]);

    msg.oper_mod = MY_S;
    if (-1 == send(arg_m.fd, &msg, sizeof(msg), 0))
        ERRLOG("send_callback");

    return 0; //重要，返回SQLITE_OK[0]才成功，否则报错
}

//查询员工函数
void my_search(int afd, sqlite3 *my_db, NETDATA_t *msg)
{
    char buf[128] = {0};
    int ret = 0;
    //组装传参结构体
    struct call
    {
        int fd;
        char name[32];
    } arg_m;
    arg_m.fd = afd;
    strcpy(arg_m.name, msg->user.name);
    //组装sql语句
    sprintf(buf, "SELECT *FROM staff WHERE name='%s'", msg->user.name);
    if (SQLITE_OK != (ret = sqlite3_exec(my_db, buf, callback, &arg_m, NULL)))
    {
        msg->oper_mod = MY_F;
        if (-1 == send(afd, msg, sizeof(NETDATA_t), 0))
        {
            ERRLOG("send_check");
        }
        printf("%s:%d --errcode[%d]--errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
    }
    msg->oper_mod = MY_S; //查询结束发送语句
    msg->aut_man = 2;
    if (-1 == send(afd, &msg, sizeof(msg), 0))
        ERRLOG("send_end");
}

//修改员工函数
void my_modify(int afd, sqlite3 *my_db, NETDATA_t *msg)
{
    char buf[256];
    int ret;
    if (1 == msg->aut_man)
    {
        //组装语句
        memset(buf, 0, sizeof(buf));
        // id|name|password|age|position|tel|addr|salary
        sprintf(buf, "UPDATE staff SET id=%d,password='%s',age=%d,position='%s',tel='%s',addr='%s',salary=%.1f WHERE name='%s'",
                msg->info.id, msg->user.password, msg->info.age, msg->info.position, msg->info.tel, msg->info.addr, msg->info.salary, msg->user.name);
        if (SQLITE_OK != (ret = sqlite3_exec(my_db, buf, NULL, NULL, NULL)))
        {
            msg->oper_mod = MY_F;
            if (-1 == send(afd, msg, sizeof(NETDATA_t), 0))
            {
                ERRLOG("send_check");
            }
            printf("%s:%d --errcode[%d]--errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
        }
    }
    else
    {
        //只允许修改自己的密码
        //组装语句
        memset(buf, 0, sizeof(buf));
        // printf("[%s]:[%s]\n", msg->user.password, msg->user.name);//debug
        sprintf(buf, "UPDATE staff SET password='%s' WHERE name='%s'", msg->user.password, msg->user.name);
        if (SQLITE_OK != (ret = sqlite3_exec(my_db, buf, NULL, NULL, NULL)))
        {
            msg->oper_mod = MY_F;
            if (-1 == send(afd, msg, sizeof(NETDATA_t), 0))
            {
                ERRLOG("send_check");
            }
            printf("%s:%d --errcode[%d]--errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
        }
    }
    msg->oper_mod = MY_S; //发送修改回复消息
    if (-1 == send(afd, msg, sizeof(NETDATA_t), 0))
        ERRLOG("modify_send error");
}

//添加员工函数
void my_add(int afd, sqlite3 *my_db, NETDATA_t *msg)
{
    char buf[256];
    int ret;

    //组装语句
    memset(buf, 0, sizeof(buf));
    // id|name|password|age|position|tel|addr|salary
    sprintf(buf, "INSERT INTO staff VALUES(%d,'%s','%s',%d,'%s','%s','%s',%.1f)",
            msg->info.id, msg->user.name, msg->user.password, msg->info.age, msg->info.position, msg->info.tel, msg->info.addr, msg->info.salary);
    if (SQLITE_OK != (ret = sqlite3_exec(my_db, buf, NULL, NULL, NULL)))
    {
        msg->oper_mod = MY_F;
        if (-1 == send(afd, msg, sizeof(NETDATA_t), 0))
        {
            ERRLOG("send_check");
        }
        printf("%s:%d --errcode[%d]--errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
    }
    msg->oper_mod = MY_S; //发送添加回复消息
    if (-1 == send(afd, msg, sizeof(NETDATA_t), 0))
        ERRLOG("modify_send error");
}

//删除员工函数
void my_del(int afd, sqlite3 *my_db, NETDATA_t *msg)
{
    char buf[256];
    int ret;

    //组装语句
    memset(buf, 0, sizeof(buf));
    // id|name|password|age|position|tel|addr|salary
    sprintf(buf, "DELETE FROM staff WHERE name='%s'",msg->user.name);
    if (SQLITE_OK != (ret = sqlite3_exec(my_db, buf, NULL, NULL, NULL)))
    {
        msg->oper_mod = MY_F;
        if (-1 == send(afd, msg, sizeof(NETDATA_t), 0))
        {
            ERRLOG("send_check");
        }
        printf("%s:%d --errcode[%d]--errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
    }
    msg->oper_mod = MY_S; //发送添加回复消息
    if (-1 == send(afd, msg, sizeof(NETDATA_t), 0))
        ERRLOG("modify_send error");
}
